﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.Filters.BloomFilter
{
    /// <summary>
    /// This class provides methods to calculate hash values out of strings. Many thanks to Bob Jenkin 
    /// (http://burtleburtle.net/bob/hash/doobs.html) for his easy description of the hash computation. 
    /// </summary>
    [Serializable]
    public static class HashFactory
    {
        /// <summary>
        /// Computes a hash value out of the specified string by using the Additive Hash method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 AdditiveHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = 0;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < stringCopy.Length; i++)
            {
                hash += stringCopy[i];
            }

            return hash % 0x811C9DC5;
        }

        /// <summary>
        /// Computes a hash value out of the specified string by using the Additive Hash method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 RotatingHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = (UInt64) value.Length;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < stringCopy.Length; ++i)
            {
                hash = (hash << 4) ^ (hash >> 28) ^ stringCopy[i];
            }

            return hash % 0x811C9DC5;
        }

        /// <summary>
        /// Computes a hash value out of the specified string by using the Once At A Time method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 OneAtATimeHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = 0;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < stringCopy.Length; i++)
            {
                hash += stringCopy[i];
                hash += (hash << 10);
                hash ^= (hash >> 6);
            }

            hash += (hash << 3);
            hash ^= (hash >> 11);
            hash += (hash << 15);

            return hash;
        }

        /// <summary>
        /// Computes a hash value out of the specified string by using the BP-Hash method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 BPHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = 0;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < value.Length; i++)
            {
                hash = hash << 7 ^ stringCopy[i];
            }

            return hash;
        }

        /// <summary>
        /// Computes a hash value out of the specified string by using the FNV-Hash method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 FNVHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = 0;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < value.Length; i++)
            {
                hash *= 0x811C9DC5;
                hash ^= stringCopy[i];
            }

            return hash;
        }

        /// <summary>
        /// Computes a hash value out of the specified string by using the SDBM-Hash method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 SDBMHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = 0;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < stringCopy.Length; i++)
            {
                hash = stringCopy[i] + (hash << 6) + (hash << 16) - hash;
            }

            return hash;
        }

        /// <summary>
        /// Computes a hash value out of the specified string by using the SAX-Hash method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 SAXHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = 0;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < stringCopy.Length; i++)
            {
                hash ^= (hash << 5) + (hash >> 2) + value[i];
            }

            return hash;
        }

        /// <summary>
        /// Computes a hash value out of the specified string by using the Bernstein Lowercase method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 BernsteinLowercaseHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = 0;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < stringCopy.Length; ++i)
            {
                hash = 33 * hash + stringCopy[i];
            }

            return hash;
        }

        /// <summary>
        /// Computes a hash value out of the specified string by using the Bernstein Invariant method.
        /// </summary>
        /// <param name="value">The specified string value for the computation.</param>
        /// <returns>The hash value of the specified string.</returns>
        public static UInt64 BernsteinInvariantHash(string value)
        {
            if (value == (string) null)
            {
                throw new ArgumentNullException("value");
            }

            UInt64 hash = 0;
            string stringCopy = (string) value.Clone();

            for (int i = 0; i < stringCopy.Length; ++i)
            {
                hash = 65 * hash + stringCopy[i];
            }

            return hash;
        }
    }
}